package com.sinodata.bsm.center.engine.event;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.sinodata.bsm.center.bean.EventRuleBean;
import com.sinodata.bsm.center.cache.DefaultEventRuleCache;
import com.sinodata.bsm.center.cache.EventRuleCache;
import com.sinodata.bsm.center.cache.EventTypeCache;
import com.sinodata.bsm.center.cache.NewEventCache;
import com.sinodata.bsm.center.cache.PropertyCache;
import com.sinodata.bsm.center.cache.ResCache;
import com.sinodata.bsm.center.cache.ResTypeCache;
import com.sinodata.bsm.center.engine.event.correlation.EventCorrelationManager;
import com.sinodata.bsm.center.expression.Expressions;
import com.sinodata.bsm.center.util.spring.SpringContextHolder;
import com.sinodata.bsm.common.constants.EventConstants;
import com.sinodata.bsm.common.utils.StringUtil;
import com.sinodata.bsm.common.vo.DefaultEventRule;
import com.sinodata.bsm.common.vo.Event;
import com.sinodata.bsm.common.vo.EventRule;
import com.sinodata.bsm.common.vo.EventType;
import com.sinodata.bsm.common.vo.Res;

/**
 * 
 * <p>
 * Description: 事件引擎
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-5-24 PM 9:14:14     liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public final class EventEngine {

    private static Map<String, EventRuleGroup> _groups = new HashMap<String, EventRuleGroup>();

    private static EventTypeCache eventTypeCache = SpringContextHolder.getBean(EventTypeCache.class);

    private static NewEventCache newEventCache = SpringContextHolder.getBean(NewEventCache.class);

    private static EventRuleCache eventRuleCache = SpringContextHolder.getBean(EventRuleCache.class);

    private static ResCache resCache = SpringContextHolder.getBean(ResCache.class);

    private static ResTypeCache resTypeCache = SpringContextHolder.getBean(ResTypeCache.class);

    private static DefaultEventRuleCache defaultEventRuleCache = SpringContextHolder.getBean(DefaultEventRuleCache.class);

    private static PropertyCache propertyCache = SpringContextHolder.getBean(PropertyCache.class);

    private static final Logger logger = Logger.getLogger(EventEngine.class);

    private static Long serialNumber = -1000000000L; //默认事件规则起始虚拟ID

    /**
     * 事件匹配
     * 
     * @param resId 资源编号
     * @param ciId 资源采集器编号
     */
    public static void matches(Long resId, Long[] propIds) {
        Set<EventRuleGroup> groups = new HashSet<EventRuleGroup>();
        for (Long propId : propIds) {
            if (propId == null) {//采集回不支持值，指标处理进入事件引擎时会设置指标Id为null
                continue;
            }
            List<EventRuleBean> rules = EventRuleBean.getAvailableRules(resId, propId);
            for (EventRuleBean eventRuleBean : rules) {
                //  eventRuleBean.matching();
                Long res = eventRuleBean.eventRule().getResId();
                Long eventTypeId = eventRuleBean.eventRule().getEventTypeId();
                EventRuleGroup g = _groups.get(res + "&" + eventTypeId);
                if (g == null) {
                    continue;
                }
                if (groups.contains(g)) {
                    continue;
                }
                groups.add(g);
                List<Event> events = g.matches(resId, propId);
                for (int j = 0; j < events.size(); j++) {
                    Event event = events.get(j);
                    EventWorkFlow.getInstance().dispatch(event);
                }
            }
        }
    }

    /**
     * 注册一个事件规则
     * 
     * @param rule
     */
    public synchronized static void registry(EventRuleBean eventRuleBean) {
        EventRule eventRule = eventRuleBean.eventRule();
        Long resId = eventRuleBean.eventRule().getResId();
        Long typeId = eventRuleBean.eventRule().getEventTypeId();
        String key = resId + "&" + typeId;
        EventRuleGroup group = _groups.get(key);
        if (group == null) {
            //TODO 传入表达式 判断是否注册的表格类型里
            group = createEventRuleGroup(resId, typeId, eventRuleBean.eventRule().getExpr(), eventRule);
            _groups.put(key, group);
        }
        group.add(eventRuleBean);
    }

    /**
     * 取消一个事件规则的注册,可能会产生新的事件
     * 
     * @param rule
     */
    public synchronized static void unregistry(EventRuleBean eventRuleBean) {
        Long resId = eventRuleBean.eventRule().getResId();
        Long typeId = eventRuleBean.eventRule().getEventTypeId();
        String key = resId + "&" + typeId;
        EventRuleGroup group = _groups.get(key);
        if (group == null) {
            return;
        }
        group.remove(eventRuleBean);
        if (eventRuleBean.eventType().getRecoverable() == EventConstants.TYPE_RECOVERABLE) {
            List<Event> events = new ArrayList<Event>();//List<Event> events = group.matches();
            EventRule eventRule = eventRuleBean.eventRule();
            if (eventRule.getObjectExpr() == null || eventRule.getObjectExpr().length() < 1) {
                events = group.matches(resId, null);
            } else {
                List<String> nodes = Expressions.parsePropNodes(eventRule.getExpr());
                for (int i = 0; i < nodes.size(); i++) {
                    Long prop = Long.parseLong(nodes.get(i).split(",")[1]);
                    events.addAll(group.matches(resId, prop));
                }
            }

            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                EventWorkFlow.getInstance().dispatch(event);
            }
        }
    }

    /**
     * 解除默认事件规则，某资源的注册
     * 
     * @param defaultEventRule
     * @param resId
     */
    public synchronized static void unregistry(DefaultEventRule defaultEventRule, Long resId) {
        Long eventTypeId = defaultEventRule.getEventTypeId();
        EventType eventType = eventTypeCache.get(eventTypeId);
        String key = resId + "&" + eventTypeId;
        EventRuleGroup group = _groups.get(key);
        if (group == null) {
            return;
        }
        String ruleKey = resId + "&" + defaultEventRule.getId() + "&" + defaultEventRule.getLevel() + "&" + (defaultEventRule.getVailTime() == null ? "" : defaultEventRule.getVailTime());
        group.removeDefault(ruleKey);
        if (eventType.getRecoverable() == EventConstants.TYPE_RECOVERABLE) {
            List<Event> events = group.matches(resId, null);// List<Event> events = group.matches();
            for (int i = 0; i < events.size(); i++) {
                Event event = events.get(i);
                EventWorkFlow.getInstance().dispatch(event);
            }
        }
    }

    /**
     * 默认事件规则转换成资源事件规则
     * 
     * @param defaultEventRule
     * @param resId
     * @return
     */
    public static EventRule transEventRule(DefaultEventRule defaultEventRule, Long resId) {
        EventRule eventRule = new EventRule();
        serialNumber = serialNumber - 1;
        eventRule.setId(serialNumber);
        eventRule.setResId(resId);
        eventRule.setEventTypeId(defaultEventRule.getEventTypeId());
        eventRule.setLevel(defaultEventRule.getLevel());
        String expr = StringUtil.replace(defaultEventRule.getExpr(), "$resid", resId + "");
        eventRule.setExpr(expr);
        if (defaultEventRule.getDuration() != null) {
            eventRule.setDuration(defaultEventRule.getDuration());
        } else {
            eventRule.setDuration(0);
        }
        String msg = StringUtil.replace(defaultEventRule.getMsg(), "$resid", resId + "");
        eventRule.setMsg(msg);
        String key = resId + "&" + defaultEventRule.getId() + "&" + defaultEventRule.getLevel() + "&" + (defaultEventRule.getVailTime() == null ? "" : defaultEventRule.getVailTime());
        eventRule.setRemarks(key);
        eventRule.setVailTime(defaultEventRule.getVailTime());
        // 是否默认规则表达式，消息表达式不设值
        eventRule.setFilterDuration(defaultEventRule.getFilterDuration());
        eventRule.setConfirmDuration(defaultEventRule.getConfirmDuration());
        eventRule.setKeyWord(defaultEventRule.getKeyWord());
        return eventRule;
    }

    /**
     * 初始化规则的状态，中心每次启动的时候需要根据原有的新事件初始化一次， 只有可恢复事件规则组需要初始化状态
     */
    public static void start() {
        //关联指标、注册事件规则
        List<EventRule> list = eventRuleCache.getAll();
        for (EventRule eventRule : list) {
            if (eventRule.getStatus() == null || eventRule.getStatus() == 0) {
                continue;
            }
            eventRuleCache.linkRuleWithProperty(eventRule);
            registry(EventRuleBean.get(eventRule.getId()));
        }
        List<Res> resList = resCache.findAll();
        for (Res res : resList) {
            Long resTypeId = res.getResTypeId();
            List<DefaultEventRule> defaultEventRuleList = new ArrayList<DefaultEventRule>();
            getDefaultEventRuleList(defaultEventRuleList, resTypeId);
            for (DefaultEventRule defaultEventRule : defaultEventRuleList) {
                if (defaultEventRule.getStatus() == null || defaultEventRule.getStatus() == 0) {
                    continue;
                }
                //转换后关联指标和注册到引擎
                EventRule eventRule = transEventRule(defaultEventRule, res.getId());
                EventRuleBean eventRuleBean = new EventRuleBean(eventRule);
                eventRuleCache.putEventRuleBean(eventRuleBean);
                eventRuleCache.linkRuleWithProperty(eventRule);
                registry(eventRuleBean);
            }
        }

        //初始化规则组
        for (Iterator<EventRuleGroup> i = _groups.values().iterator(); i.hasNext();) {
            EventRuleGroup g = i.next();
            if (!(g instanceof ResumableRuleGroup) && !(g instanceof TableResumableRuleGroup)) {
                break;
            }
            List<Event> events = newEventCache.getNewEvents(g.resId, g.eventTypeId, null);
            if (g instanceof ResumableRuleGroup) {
                int status = EventConstants.LEVEL_NORMAL;
                for (int j = 0; j < events.size(); j++) {
                    int level = events.get(j).getLevel();
                    if (level > status) {
                        status = level;
                    }
                }
                ((ResumableRuleGroup) g).setStatus(status);
            }
            //规则组不需要刷新状态
            //            if (g instanceof TableResumableRuleGroup) {
            //                Map<String, List<Event>> map = getGroupByObjectId(events);
            //                Iterator<String> it = map.keySet().iterator();
            //                while (it.hasNext()) {
            //                    int status = EventConstants.LEVEL_NORMAL;
            //                    String objectId = it.next();
            //                    List<Event> groupEvent = map.get(objectId);
            //                    for (Event event : groupEvent) {
            //                        int level = event.getLevel();
            //                        if (level > status) {
            //                            status = level;
            //                        }
            //                    }
            //                    ((TableResumableRuleGroup) g).setStatus(objectId, status);
            //                }
            //            }
        }
        logger.info("[TIP]>>>>>Event engine start");
        //EventCorrelationManager.getInstance();
    }

    /**
     * 不可恢事件的话,不需要刷新
     * 
     * @param resId
     * @param typeId
     */
    public synchronized static void refreshStatus(Long resId, Long eventTypeId) {
        String key = resId + "&" + eventTypeId;
        EventRuleGroup g = _groups.get(key);
        if (!(g instanceof ResumableRuleGroup) && !(g instanceof TableResumableRuleGroup)) {
            return;
        }
        List<Event> events = newEventCache.getNewEvents(resId, eventTypeId, null);
        if (g instanceof ResumableRuleGroup) {
            int status = EventConstants.LEVEL_NORMAL;
            for (int j = 0; j < events.size(); j++) {
                int level = events.get(j).getLevel();
                if (level > status) {
                    status = level;
                }
            }
            ((ResumableRuleGroup) g).setStatus(status);
        }
        //表格事件规则组不需要刷新状态
        //        if (g instanceof TableUnresumableRuleGroup) {
        //            Map<String, List<Event>> map = getGroupByObjectId(events);
        //            Iterator<String> it = map.keySet().iterator();
        //            while (it.hasNext()) {
        //                int status = EventConstants.LEVEL_NORMAL;
        //                String objectId = it.next();
        //                List<Event> list = map.get(objectId);
        //                for (Event event : list) {
        //                    int level = event.getLevel();
        //                    if (level > status) {
        //                        status = level;
        //                    }
        //                }
        //                ((TableResumableRuleGroup) g).setStatus(objectId, status);
        //            }
        //        }
    }

    /**
     * 把事件按对象ID分组
     * 
     * @param events
     * @return
     */
    //    private static Map<String, List<Event>> getGroupByObjectId(List<Event> events) {
    //        Map<String, List<Event>> map = new HashMap<String, List<Event>>();
    //        if (events == null || events.size() == 0) {
    //            return map;
    //        }
    //        for (Event event : events) {
    //            String objectId = event.getObjectId();
    //            List<Event> list = map.get(objectId);
    //            if (list == null) {
    //                list = new ArrayList<Event>();
    //            }
    //            list.add(event);
    //            map.put(objectId, list);
    //        }
    //        return map;
    //    }
    /**
     * 根据事件的是否可恢复性创建一个规则组
     * 
     * @param resId
     * @param typeId
     * @return
     */
    private static EventRuleGroup createEventRuleGroup(Long resId, Long typeId, String expr, EventRule eventRule) {
        EventType type = eventTypeCache.get(typeId);
        EventRuleGroup group = null;
        if (Expressions.parseTableExpr(expr).size() == 1) {//TODO 根据表达式 判断是否 创建表格事件规则组
            if (type.getRecoverable() == EventConstants.TYPE_RECOVERABLE) {
                group = new TableResumableRuleGroup(resId, typeId);
            } else {
                group = new TableUnresumableRuleGroup(resId, typeId);
            }
            return group;
        }
        if (type.getRecoverable() == EventConstants.TYPE_RECOVERABLE) {
            group = new ResumableRuleGroup(resId, typeId);
        } else {
            group = new UnresumableRuleGroup(resId, typeId);
        }
        return group;
    }

    /**
     * 递归获取默认事件规则，默认事件规则继承父类别定义的事件规则
     * 
     * @param result
     * @param resTypeId
     * @return
     */
    private static List<DefaultEventRule> getDefaultEventRuleList(List<DefaultEventRule> result, Long resTypeId) {
        Long parentId = resTypeCache.get(resTypeId).getParentId();
        if (parentId != null) {
            getDefaultEventRuleList(result, parentId);
        }
        List<DefaultEventRule> temp = defaultEventRuleCache.getDefaultEventRuleByResTypeId(resTypeId);
        if (temp != null && temp.size() > 0) {
            result.addAll(temp);
        }
        return result;
    }

}
